home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / main.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  44KB  |  2,015 lines

  1. /* Main-level network program:
  2.  * initialization
  3.  * keyboard processing
  4.  * generic user commands
  5.  *
  6.  * Copyright 1991 Phil Karn, KA9Q
  7.  */
  8. #include <stdio.h>
  9. #include <time.h>
  10. #if     defined(__TURBOC__) && defined(MSDOS)
  11. #include <fcntl.h>
  12. #include <dos.h>
  13. #include <io.h>
  14. #include <conio.h>
  15. #include <ctype.h>
  16. #include <dir.h>
  17. #endif
  18. #ifdef UNIX
  19. #include <fcntl.h>
  20. #endif
  21. #include "global.h"
  22. #include "config.h"
  23. #ifdef  ANSIPROTO
  24. #include <stdarg.h>
  25. #endif
  26. #include "mbuf.h"
  27. #include "timer.h"
  28. #include "proc.h"
  29. #include "iface.h"
  30. #include "ip.h"
  31. #include "tcp.h"
  32. #include "udp.h"
  33. #include "ax25.h"
  34. #include "kiss.h"
  35. #ifdef ETHER
  36. #include "enet.h"
  37. #endif
  38. #include "netrom.h"
  39. #include "ftpcli.h"
  40. #include "telnet.h"
  41. #include "tty.h"
  42. #include "session.h"
  43. #include "hardware.h"
  44. #include "usock.h"
  45. #include "socket.h"
  46. #ifdef LZW
  47. #include "lzw.h"
  48. #endif
  49. #include "cmdparse.h"
  50. #include "commands.h"
  51. #include "daemon.h"
  52. #include "devparam.h"
  53. #include "domain.h"
  54. #include "files.h"
  55. #include "main.h"
  56. #include "mailbox.h"
  57. #include "remote.h"
  58. #include "trace.h"
  59. #ifdef fprintf
  60. #undef fprintf
  61. #endif
  62. #include "mailutil.h"
  63. #include "smtp.h"
  64. #include "version.h"
  65.  
  66. #undef BETA 1
  67. #ifdef BSAHAX
  68. #define BETA 1
  69. #endif
  70.  
  71. #ifdef XSPAWN
  72. #include "xspawn.h"
  73. #endif
  74.  
  75. #ifndef UNIX
  76. /* The following is from the Borland Runtime Library Version 3.0 :
  77.  * Copyright (c) 1987, 1990 by Borland International
  78.  */
  79. typedef struct
  80. {
  81.     unsigned char windowx1;
  82.     unsigned char windowy1;
  83.     unsigned char windowx2;
  84.     unsigned char windowy2;
  85.     unsigned char attribute;
  86.     unsigned char normattr;
  87.     unsigned char currmode;
  88.     unsigned char screenheight;
  89.     unsigned char screenwidth;
  90.     unsigned char graphicsmode;
  91.     unsigned char snow;
  92.     union {
  93.         char far * p;
  94.         struct { unsigned off,seg; } u;
  95.     } displayptr;
  96. } VIDEOREC;
  97. extern VIDEOREC _video;
  98. #endif
  99.  
  100. extern struct cmds DFAR Cmds[],DFAR Startcmds[],DFAR Stopcmds[],Attab[];
  101.  
  102. #if     (!defined(MSDOS) || defined(ESCAPE))    /* PC uses F-10 key always */
  103. static char Escape = 0x1d;      /* default escape character is ^] */
  104. #endif
  105.  
  106. #ifdef __TURBOC__
  107. int dofstat __ARGS((void));
  108. #endif
  109. static char Prompt[] = "net> ";
  110. char NoRead[] = "Can't read %s: %s\n";
  111. char Badhost[] = "Unknown host %s\n";
  112. char Badinterface[] = "Interface \"%s\" unknown\n";
  113. char Existingiface[] = "Interface %s already exists\n";
  114. char Nospace[] = "No space!!\n";    /* Generic malloc fail message */
  115. char Nosversion[] = "KA9Q NOS version %s\n";
  116. #ifdef MSDOS
  117. char NosLoadInfo[] = "NOS load info: CS=0x%04x DS=0x%04x";
  118. #endif
  119. char Noperm[] = "Permission denied.\n";
  120. char Nosock[] = "Can't create socket\n";
  121. char SysopBusy[] = "The sysop is busy. Try again later.\n";
  122. char *Hostname;
  123. char *Motd;                     /* Message Of The Day */
  124. int Attended = TRUE;            /* default to attended mode */
  125. int ThirdParty = TRUE;                  /* Allows 3rd party mail by default */
  126. int main_exit;          /* from main program (flag) */
  127. int DosPrompt;          /* Use a dos-like prompt */
  128. int Mprunning;          /* flag for other parts (domain) to signal
  129.              * that we are fully configured running.
  130.              */
  131. struct proc *Cmdpp;
  132. #ifndef UNIX
  133. struct proc *Display;
  134. #endif
  135. #ifdef  LZW
  136. int Lzwmode = LZWCOMPACT;
  137. int16 Lzwbits = LZWBITS;
  138. #endif
  139.  
  140. #ifdef TRACE
  141. int Tracesession = 1;
  142. struct session *Trace = NULLSESSION;
  143. #endif
  144.  
  145. static char *DumpAddr = NULL;           /* Memory dump pointer */
  146. static FILE *Logfp;
  147. time_t StartTime;        /* Time that NOS was started */
  148. static int Verbose;
  149.  
  150. static void ctohex __ARGS((char *buf,int16 c));
  151. static void fmtline __ARGS((int16 addr,char *buf,int16 len));
  152. extern void assign_filenames __ARGS((char *));
  153. static void logcmd __ARGS((char *));
  154. #if 0
  155. void status();
  156. #endif
  157.  
  158. int Numrows,Numcols;    /* screen size at startup - WG7J */
  159. struct hist *Histry;    /* command recall stuff */
  160. int Histrysize;
  161. int Maxhistory = 10;
  162.  
  163. #ifdef UNIX
  164. static char **origargv;
  165. #endif
  166.  
  167. int
  168. #ifdef PROTOTYPES
  169. main(int argc, char **argv)
  170. #else
  171. main(argc,argv)
  172. int argc;
  173. char *argv[];
  174. #endif
  175. {
  176.     char *inbuf,*intmp;
  177.     FILE *fp;
  178.     struct daemon *tp;
  179.     struct mbuf *bp;
  180.     int c;
  181. #ifdef UNIX
  182.     int no_itimer, did_init;
  183.     char *trace_sm = 0;
  184.     char *def_sm = 0;
  185.     static int oops;
  186. #else
  187.     struct text_info ti;
  188. #endif
  189.     struct cur_dirs dirs;
  190.  
  191. #ifdef UNIX
  192.     if (oops++)
  193.     {
  194.     iostop();
  195.     fprintf(stderr, "NOS PANIC: NOS main re-entered.\n");
  196.     fflush(stderr);
  197.     fflush(stdout);
  198.     kill(getpid(), 11);
  199.     }
  200.     origargv = argv;
  201. #endif
  202. #ifdef XSPAWN
  203.     /* These vectors WILL be intercepted by NOS in COMMAND.ASM
  204.        Go ahead and tell XSPAWN to save their current state, now.
  205.        Vector 0x23 is also used by NOS, but is ALREADY being preserved
  206.        by the XSPAWN routines        */
  207.     addvect (8, CURRENT);
  208.     addvect (0x10, CURRENT);
  209.     addvect (0x13, CURRENT);
  210.     addvect (0x1b, CURRENT);
  211.     addvect (0x21, CURRENT);
  212.     addvect (0x24, CURRENT);
  213.     addvect (0x28, CURRENT);
  214. #endif
  215.  
  216.     setversion();
  217.     StartTime = time(&StartTime);           /* NOS Start_Up time */
  218. #ifdef UNIX
  219.     SRANDOM((getpid() << 16) ^ time((long *) 0));
  220. #else
  221.     randomize();
  222. #endif
  223.  
  224. #ifdef UNIX
  225.     no_itimer = 0;
  226. #else
  227.     /* Borland's library calls int10. Some vga mode utilities do not
  228.      * report the screen sizes correctly into the internal _video structure.
  229.      * This can cause the screen size to be faulty in the gettextinfo call.
  230.      * Instead, read the BIOS data area to get the correct screen info,
  231.      * and update the _video structure for later calls to
  232.      * gettextinfo(), clrscr(), etc... - WG7J
  233.      *
  234.      * If this doesn't work, you can now overwrite the values with
  235.      * the -r and -c command line options - WG7J
  236.      */
  237.     Numrows = (int) *(char far *)MK_FP(0x40,0x84) + 1;
  238.     gettextinfo(&ti);
  239.     Numcols = ti.screenwidth;
  240. /*
  241.     Numrows = ti.screenheight;
  242. */
  243.  
  244.     if(Numrows == 1)
  245.            Numrows = 25;
  246. #endif
  247.  
  248. #ifdef UNIX
  249.     did_init = 0;
  250.     while((c = getopt(argc,argv,"s:d:x:f:nbvDS:T:")) != EOF){
  251. #else
  252.     while((c = getopt(argc,argv,"s:d:r:c:x:f:nbvD")) != EOF){
  253. #endif
  254.         switch(c){
  255. #ifdef TRACE
  256.     case 'n':
  257.         Tracesession = 0; /* No session for tracing */
  258.         break;
  259. #endif
  260. #ifndef UNIX
  261.     case 'r':   /* Number of rows on screen */
  262.         Numrows = atoi(optarg);
  263.         break;
  264.     case 'c':   /* Number of columns on screen */
  265.         Numcols = atoi(optarg);
  266.         break;
  267. #endif
  268.     case 's':   /* Number of sockets */
  269.             Nusock = atoi(optarg);
  270.             break;
  271. #ifdef XSPAWN
  272.     case 'x':   /* Path for XSWAP temp file */
  273.         _swappath = strdup(optarg);
  274.         break;
  275. #endif
  276. #if defined(MSDOS) || defined(UNIX)
  277.     case 'f':
  278.         assign_filenames(optarg);
  279. #ifdef UNIX
  280.         did_init = 1;
  281. #endif
  282.         break;
  283. #endif
  284.     case 'd':   /* Root directory for various files */
  285.             initroot(optarg);
  286.             break;
  287. #ifdef  __TURBOC__
  288.         case 'b':       /* Use BIOS for screen output */
  289.             directvideo = 0;
  290.             break;
  291. #endif
  292.         case 'v':
  293.             Verbose = 1;
  294.             break;
  295. #ifdef UNIX
  296.     case 'D':
  297.         no_itimer = 1;    /* for debugging */
  298.         break;
  299.     case 'S':
  300.         if (sm_lookup(optarg, 0))
  301.         def_sm = optarg;
  302.         else
  303.         printf("No session manager \"%s\", using default\n", optarg);
  304.         break;
  305.     case 'T':
  306.         if (sm_lookup(optarg, 0))
  307.         trace_sm = optarg;
  308.         else
  309.         printf("Session manager for trace not found, using default\n");
  310.         break;
  311. #endif
  312.         }
  313.     }
  314. #ifdef UNIX
  315.     if (!did_init)
  316.     assign_filenames(".nosrc");
  317. #endif
  318.  
  319. #ifndef UNIX
  320.     /* Set the internal structure, in case there was a command
  321.      * line overwrite - WG7J
  322.      */
  323.     _video.screenheight = (unsigned char)Numrows;
  324.     _video.windowx2 = (unsigned char)(Numcols - 1);
  325.     _video.windowy2 = (unsigned char)(Numrows - 1);
  326. #endif
  327.  
  328.     kinit();
  329.     ipinit();
  330. #ifdef UNIX
  331.     ioinit(no_itimer);
  332. #else
  333.     ioinit();
  334. #endif
  335.     sockinit();
  336.     Cmdpp = mainproc("cmdintrp");
  337.  
  338.     Sessions = (struct session *)callocw(Nsessions,sizeof(struct session));
  339. #ifdef TRACE
  340.     if(Tracesession)
  341. #ifdef UNIX
  342.     {
  343.     if (!trace_sm)
  344.         trace_sm = Trace_sessmgr;
  345.     Trace = sm_newsession(trace_sm, NULLCHAR, TRACESESSION, 0);
  346.     }
  347. #else
  348.     Trace = newsession(NULLCHAR,TRACESESSION,0);
  349. #endif
  350. #endif
  351. #ifdef UNIX
  352.     if (!def_sm)
  353.     def_sm = Command_sessmgr;
  354.     Command = Lastcurr = sm_newsession(def_sm, NULLCHAR, COMMAND, 0);
  355. #else
  356.     Command = Lastcurr = newsession(NULLCHAR,COMMAND,0);
  357. #endif
  358.     /* Flow mode is set AFTER we've read the autoexec file !
  359.      * this keeps systems from locking up if the reboot is unattended - WG7J
  360.      */
  361. #ifndef UNIX
  362.     Display = newproc("display",250,display,0,NULLCHAR,NULL,0);
  363. #endif
  364.     tprintf(Nosversion,Version);
  365.     tputs(Version2);
  366.     tputs("Copyright 1991 by Phil Karn (KA9Q) and contributors.\n");
  367. #ifdef BETA
  368.     tputs("This is a BETA version; be warned !\n");
  369. #endif
  370.  
  371.     rflush();
  372.  
  373.     /* Start background Daemons */
  374.     for(tp=Daemons;;tp++){
  375.         if(tp->name == NULLCHAR)
  376.             break;
  377.         newproc(tp->name,tp->stksize,tp->fp,0,NULLCHAR,NULL,0);
  378.     }
  379.  
  380.     init_dirs(&dirs);
  381.     Command->curdirs=&dirs;
  382.  
  383.     if(optind < argc){
  384.         /* Read startup file named on command line */
  385.         if((fp = fopen(argv[optind],READ_TEXT)) == NULLFILE)
  386.         tprintf(NoRead,argv[optind],sys_errlist[errno]);
  387.     } else {
  388.         /* Read default startup file named in files.c (autoexec.nos) */
  389.         if((fp = fopen(Startup,READ_TEXT)) == NULLFILE)
  390.         tprintf(NoRead,Startup,sys_errlist[errno]);
  391.     }
  392.     if(fp != NULLFILE){
  393.         inbuf = mallocw(BUFSIZ);
  394.         intmp = mallocw(BUFSIZ);
  395.         while(fgets(inbuf,BUFSIZ,fp) != NULLCHAR){
  396.             strcpy(intmp,inbuf);
  397.             if(Verbose){
  398.                 tprintf("%s",intmp);
  399.                 rflush();
  400.             }
  401.             if(cmdparse(Cmds,inbuf,NULL) != 0){
  402.                 tprintf("input line: %s",intmp);
  403.         rflush();
  404.         }
  405.         }
  406.         fclose(fp);
  407.         free(inbuf);
  408.         free(intmp);
  409.     }
  410.  
  411.     Mprunning = 1;  /* we are on speed now */
  412.     Command->flowmode = 1;      /* set 'more' paging on command screen */
  413.  
  414.     /* Now loop forever, processing commands */
  415.     for(;;){
  416.     if(DosPrompt)
  417.         tprintf("%s ",dirs.dir);
  418.     tputs(Prompt);
  419.         usflush(Command->output);
  420.         if(recv_mbuf(Command->input,&bp,0,NULLCHAR,0) != -1){
  421.         logcmd(bp->data);
  422.         (void)cmdparse(Cmds,bp->data,Lastcurr);
  423.             free_p(bp);
  424.         }
  425.     }
  426. }
  427. /* Keyboard input process */
  428. /* Modified to support F-key session switching,
  429.  * from the WNOS3 sources - WG7J
  430.  */
  431. void
  432. keyboard(i,v1,v2)
  433. int i;
  434. void *v1;
  435. void *v2;
  436. {
  437.     int c;
  438.     struct mbuf *bp;
  439.     register int j,k;
  440.     struct session *sp;
  441.  
  442.     /* Keyboard process loop */
  443.     for(;;){
  444.         c = kbread();
  445. #if     (!defined(MSDOS) || defined(ESCAPE))
  446.         if(c == Escape && Escape != 0)
  447.             c = -2;
  448. #endif
  449.         if(c == -2 && Current != Command){
  450.             /* Save current tty mode and set cooked */
  451.             swapscreen(Current,Command);
  452.             Lastcurr = Current;
  453.             Current = Command;
  454.             /* set 'more' paging on command screen */
  455.             Command->flowmode = 1;
  456.         }
  457.     if((c < -2) && (c > -12)) {             /* F1 to F9 pressed */
  458. #ifdef TRACE
  459.         /* If F9 is pressed, -11 is returned and we swap to Trace - WG7J */
  460.         if(c == -11) {
  461.         if(Tracesession) {
  462.             if(Current != Trace){
  463.             /* Save current tty mode and set cooked */
  464.             swapscreen(Current,Trace);
  465.             Lastcurr = Current;
  466.             Current = Trace;
  467.             /* turn off 'more' paging on trace screen */
  468.             Trace->flowmode = 0;
  469.             } else {
  470.             /* Toggle back to previous session */
  471.             swapscreen(Trace,Lastcurr);
  472.             Current = Lastcurr;
  473.             Lastcurr = Trace;
  474.             }
  475.         }
  476.         } else {
  477. #endif
  478.         k = (-1 * c) - 2;
  479.                 for(sp = Sessions, j = 0; sp < &Sessions[Nsessions]; sp++) {
  480.                     if(sp->type == COMMAND)
  481.                         continue;
  482.                     j++;
  483.                     if(sp->type != FREE && j == k) {
  484.                         swapscreen(Current,sp);
  485.                         Lastcurr = Current;
  486.                         Current = sp;
  487.                         break;
  488.                     }
  489.                 }
  490. #ifdef TRACE
  491.         }
  492. #endif
  493.     }
  494.     
  495.     Current->row = Numrows;
  496.         psignal(&Current->row,1);
  497.         if(c >= 0){
  498. #ifdef UNIX
  499.             if (Current->morewait) /* end display pause, if any */
  500.                 Current->morewait = 2;
  501. #endif
  502.             /* If the screen driver was in morewait state, this char
  503.              * has woken him up. Toss it so it doesn't also get taken
  504.              * as normal input. If the char was a command escape,
  505.              * however, it will be accepted; this gives the user
  506.              * a way out of lengthy output.
  507.              */
  508.             if(!Current->morewait
  509.          && (bp = ttydriv(Current,c)) != NULLBUF){
  510.                 send_mbuf(Current->input,bp,0,NULLCHAR,0);
  511.             }
  512.         }
  513.     }
  514. }
  515.  
  516. extern int Kblocked;
  517. extern char *Kbpasswd;
  518. #ifdef LOCK
  519.  
  520. /*Lock the keyboard*/
  521. int
  522. dolock(argc,argv,p)
  523. int argc;
  524. char *argv[];
  525. void *p;
  526. {
  527.  
  528.     extern char Noperm[];
  529.  
  530.     /*allow only keyboard users to access the lock command*/
  531.     if(Curproc->input != Command->input) {
  532.         tputs(Noperm);
  533.         return 0;
  534.     }
  535.     if(argc == 1) {
  536.         if(Kbpasswd == NULLCHAR)
  537.             tputs("Set password first\n");
  538.         else {
  539.             Kblocked = 1;
  540.             tputs("Keyboard locked\n");
  541.             Command->ttystate.echo = 0; /* Turn input echoing off! */
  542.         }
  543.     return 0;
  544.     }
  545.     if(argc == 3) {
  546.     if(*argv[1] == 'p') {   /*set the password*/
  547.         if(Kbpasswd != NULLCHAR){
  548.         free(Kbpasswd);
  549.         Kbpasswd = NULLCHAR;        /* reset the pointer */
  550.         }
  551.     if(!strlen(argv[2]))
  552.         return 0;           /* clearing the buffer */
  553.     Kbpasswd = strdup(argv[2]);
  554.     return 0;
  555.     }
  556.     }
  557.  
  558.     tputs("Usage: lock password \"<unlock password>\"\n"
  559.       "or    'lock' to lock the keyboard\n");
  560.  
  561.     return 0;
  562. }
  563.  
  564. #endif
  565.  
  566. #ifdef ALLCMD
  567. /* Standard commands called from main */
  568. int
  569. dodelete(argc,argv,p)
  570. int argc;
  571. char *argv[];
  572. void *p;
  573. {
  574.     int i;
  575.     char fname[128];
  576.  
  577.     for(i=1;i < argc; i++){
  578.     strcpy(fname,make_fname(Command->curdirs->dir,argv[i]));
  579.     if(unlink(fname) == -1){
  580.         tprintf("Can't delete %s: %s\n",fname,sys_errlist[errno]);
  581.         }
  582.     }
  583.     return 0;
  584. }
  585. int
  586. dorename(argc,argv,p)
  587. int argc;
  588. char *argv[];
  589. void *p;
  590. {
  591.     char fname1[128];
  592.     char fname2[128];
  593.  
  594.     strcpy(fname1,make_fname(Command->curdirs->dir,argv[1]));
  595.     strcpy(fname2,make_fname(Command->curdirs->dir,argv[2]));
  596.     if(rename(fname1,fname2) == -1)
  597.         tprintf("Can't rename: %s\n",sys_errlist[errno]);
  598.     return 0;
  599. }
  600. int
  601. docopy(argc,argv,p)
  602. int argc;
  603. char *argv[];
  604. void *p;
  605. {
  606.     FILE *old, *new;
  607.     int ch;
  608.     unsigned char count;
  609.     char fname[128];
  610.  
  611.     strcpy(fname,make_fname(Command->curdirs->dir,argv[1]));
  612.     if((old = fopen(fname,"rb")) == NULL) {
  613.     tprintf("Can't open %s: %s\n",fname,sys_errlist[errno]);
  614.     return 1;
  615.     }
  616.     strcpy(fname,make_fname(Command->curdirs->dir,argv[2]));
  617.     if((new = fopen(fname,"wb")) == NULL) {
  618.     tprintf("Can't open %s: %s\n",fname,sys_errlist[errno]);
  619.     fclose(old);
  620.     return 1;
  621.     }
  622.     /* Now go copy */
  623.     count = 0;
  624.     while((ch = fgetc(old)) != EOF) {
  625.     fputc(ch,new);
  626.     if(!(++count))      /* be polite to other users */
  627.         pwait(NULL);
  628.     }
  629.     fclose(old);
  630.     fclose(new);
  631.     return 0;
  632. }
  633. #endif /*ALLCMD*/
  634.  
  635. /*this is also called from the remote-server for the 'exit' command - WG7J*/
  636. void
  637. where_outta_here(resetme)
  638. int resetme;
  639. {
  640.     time_t StopTime;
  641.     FILE *fp;
  642.     char *inbuf,*intmp;
  643.  
  644.     /* Execute sequence of commands taken from file "~/onexit.nos" */
  645.     /* From iw0cnb */
  646.     if((fp = fopen(Onexit,READ_TEXT)) != NULLFILE){
  647.         inbuf = mallocw(BUFSIZ);
  648.         intmp = mallocw(BUFSIZ);
  649.         while(fgets(inbuf,BUFSIZ,fp) != NULLCHAR){
  650.             strcpy(intmp,inbuf);
  651.         if(Verbose){
  652.                 tprintf("%s",intmp);
  653.                 rflush();
  654.         }
  655.         if(cmdparse(Cmds,inbuf,NULL) != 0){
  656.                 tprintf("input line: %s",intmp);
  657.             }
  658.         }
  659.         fclose(fp);
  660.         free(inbuf);
  661.         free(intmp);
  662.     }
  663.     StopTime = time(&StopTime);
  664.     main_exit = TRUE;       /* let everyone know we're out of here */
  665.     reset_all();
  666.     if(Dfile_updater != NULLPROC)
  667.         alert(Dfile_updater,0); /* don't wait for timeout */
  668.     pause(3000);    /* Let it finish */
  669. #ifdef TRACE
  670.     shuttrace();
  671. #endif
  672.     log(-1,"NOS was stopped");
  673.     if(Logfp){
  674.         fclose(Logfp);
  675.         Logfp = NULLFILE;
  676.     }
  677. #ifdef UNIX
  678.     detach_all_asy();        /* make sure everything is unlocked */
  679.     pwait(NULL);
  680. #endif
  681.     iostop();
  682.     if(resetme)
  683. #ifdef UNIX
  684.     {
  685.     if (fork() == 0)
  686.         abort();
  687.     execvp(origargv[0], origargv); /* re-run NOS */
  688.     }
  689. #else
  690.     sysreset();
  691. #endif
  692.     exit(0);
  693. }
  694.  
  695. #if 0
  696. extern struct proc *Aproc;
  697. #endif
  698.  
  699. int
  700. doexit(argc,argv,p)
  701. int argc;
  702. char *argv[];
  703. void *p;
  704. {
  705.     time_t nowtime, elapsedtime;
  706.     unsigned int days,hrs,mins,secs;
  707.  
  708. #if 0                /* you can't have 2 at's at the same time?? */
  709.     if(Curproc == Aproc)     /* From the AT command */
  710. #endif
  711.     if (strnicmp(Curproc->name, "at ", 3) == 0)
  712.         where_outta_here(0);
  713.  
  714.     if(Curproc->input == Command->input) {  /* From keyboard */
  715.         Command->ttystate.edit = Command->ttystate.echo = 0;
  716.         if(toupper(keywait("Are you sure? ",0))=='Y') {
  717.             nowtime = time(&nowtime);                       /* current time */
  718.             elapsedtime = nowtime - StartTime;              /* nos elapsed time */
  719.             secs = elapsedtime % 60;
  720.             elapsedtime = elapsedtime / 60;
  721.             mins = elapsedtime % 60;
  722.             elapsedtime = elapsedtime / 60;
  723.             hrs = elapsedtime % 24;
  724.             elapsedtime = elapsedtime / 24;
  725.             days = elapsedtime;
  726.             tprintf("NOS Exiting - Runtime => %u days:%02u hours:%02u minutes:%02u seconds.\n",days,hrs,mins,secs);
  727.             where_outta_here(0); /*No reset!*/
  728.         }
  729.         Command->ttystate.edit = Command->ttystate.echo = 1;
  730.         return 0;
  731.    }
  732.    /* Anything else; probably mailbox-sysop */
  733.    return -2;
  734. }
  735.  
  736. extern char Chostname[];
  737.  
  738. int
  739. dohostname(argc,argv,p)
  740. int argc;
  741. char *argv[];
  742. void *p;
  743. {
  744. #ifdef CONVERS
  745.     char *cp;
  746. #endif
  747.  
  748.     if(argc < 2)
  749.         tprintf("%s\n",Hostname);
  750.     else {
  751.         struct iface *ifp;
  752.         char *name;
  753.  
  754.     if((ifp = if_lookup(argv[1])) != NULLIF){
  755.             if((name = resolve_a(ifp->addr, FALSE)) == NULLCHAR){
  756.                 tprintf("Interface address not resolved\n");
  757.                 return 1;
  758.             } else {
  759.                 if(Hostname != NULLCHAR)
  760.                     free(Hostname);
  761.                 Hostname = name;
  762.                 tprintf("Hostname set to %s\n", name );
  763.             }
  764.         } else {
  765.             if(Hostname != NULLCHAR)
  766.                 free(Hostname);
  767.             Hostname = strdup(argv[1]);
  768.             /* Remove trailing dot */
  769.             if(Hostname[strlen(Hostname)] == '.')
  770.                 Hostname[strlen(Hostname)] = '.';
  771.         }
  772. #ifdef CONVERS
  773.     /* If convers hostname not set yet, set it to first 10 chars
  774.      * of the hostname. If there are '.' from the right, cut off
  775.      * before that. - WG7J
  776.      */
  777.     if(Chostname[0] == '\0') {
  778.         strncpy(Chostname,Hostname,CNAMELEN);
  779.         if((cp = strrchr(Chostname,'.')) != NULLCHAR)
  780.         *cp = '\0';
  781.     }
  782. #endif
  783.     }
  784.     return 0;
  785. }
  786.  
  787. int
  788. dolog(argc,argv,p)
  789. int argc;
  790. char *argv[];
  791. void *p;
  792. {
  793.     static char *logname;
  794.  
  795.     if(argc < 2){
  796.         if(Logfp)
  797.             tprintf("Logging to %s\n",logname);
  798.         else
  799.             tprintf("Logging off\n");
  800.         return 0;
  801.     }
  802.     if(Logfp){
  803.         log(-1,"NOS log closed");
  804.         fclose(Logfp);
  805.         Logfp = NULLFILE;
  806.         free(logname);
  807.         logname = NULLCHAR;
  808.     }
  809.     if(strcmp(argv[1],"stop") != 0){
  810.         logname = strdup(argv[1]);
  811.         Logfp = fopen(logname,APPEND_TEXT);
  812.         log(-1,"NOS v%s was started at %s", Version, ctime(&StartTime));
  813. #ifdef  MSDOS
  814.     log(-1,NosLoadInfo, _CS, _DS);
  815. #endif
  816.     }
  817.     return 0;
  818. }
  819. int
  820. dohelp(argc,argv,p)
  821. int argc;
  822. char *argv[];
  823. void *p;
  824. {
  825.     register struct cmds *cmdp;
  826.     int i;
  827.     char buf[66];
  828.  
  829.     tprintf("Main commands:\n");
  830.     memset(buf,' ',sizeof(buf));
  831.     buf[64] = '\n';
  832.     buf[65] = '\0';
  833.     for(i=0,cmdp = Cmds;cmdp->name != NULL;cmdp++,i = (i+1)%4){
  834.         strncpy(&buf[i*16],cmdp->name,strlen(cmdp->name));
  835.         if(i == 3){
  836.             tprintf(buf);
  837.             memset(buf,' ',sizeof(buf));
  838.             buf[64] = '\n';
  839.             buf[65] = '\0';
  840.         }
  841.     }
  842.     if(i != 0)
  843.         tprintf(buf);
  844.     return 0;
  845. }
  846.  
  847. /* Attach an interface
  848.  * Syntax: attach <hw type> <I/O address> <vector> <mode> <label> <bufsize> [<speed>]
  849.  */
  850. int
  851. doattach(argc,argv,p)
  852. int argc;
  853. char *argv[];
  854. void *p;
  855. {
  856.     return subcmd(Attab,argc,argv,p);
  857. }
  858. /* Manipulate I/O device parameters */
  859. int
  860. doparam(argc,argv,p)
  861. int argc;
  862. char *argv[];
  863. void *p;
  864. {
  865.     int param,set;
  866.     int32 val;
  867.     register struct iface *ifp;
  868.  
  869.     if((ifp = if_lookup(argv[1])) == NULLIF){
  870.     tprintf(Badinterface,argv[1]);
  871.         return 1;
  872.     }
  873.     if(ifp->ioctl == NULL){
  874.         tprintf("Not supported\n");
  875.         return 1;
  876.     }
  877.     if(argc < 3){
  878.         for(param=1;param<=16;param++){
  879.             val = (*ifp->ioctl)(ifp,param,FALSE,0L);
  880.             if(val != -1)
  881.                 tprintf("%s: %ld\n",parmname(param),val);
  882.         }
  883.         return 0;
  884.     }
  885.     param = devparam(argv[2]);
  886.     if(param == -1){
  887.         tprintf("Unknown parameter %s\n",argv[2]);
  888.         return 1;
  889.     }
  890.     if(argc < 4){
  891.         set = FALSE;
  892.         val = 0L;
  893.     } else {
  894.         set = TRUE;
  895.         val = atol(argv[3]);
  896.     }
  897.     val = (*ifp->ioctl)(ifp,param,set,val);
  898.     if(val == -1){
  899.         tprintf("Parameter %s not supported\n",argv[2]);
  900.     } else {
  901.         tprintf("%s: %ld\n",parmname(param),val);
  902.     }
  903.     return 0;       
  904. }
  905.  
  906. /* Display or set IP interface control flags */
  907. int
  908. domode(argc,argv,p)
  909. int argc;
  910. char *argv[];
  911. void *p;
  912. {
  913.     register struct iface *ifp;
  914.  
  915.     if((ifp = if_lookup(argv[1])) == NULLIF){
  916.     tprintf(Badinterface,argv[1]);
  917.         return 1;
  918.     }
  919.     if(argc < 3){
  920.         tprintf("%s: %s\n",ifp->name,
  921.          (ifp->flags & CONNECT_MODE) ? "VC mode" : "Datagram mode");
  922.         return 0;
  923.     }
  924.     switch(argv[2][0]){
  925.     case 'v':
  926.     case 'c':
  927.     case 'V':
  928.     case 'C':
  929.     ifp->flags |= CONNECT_MODE;
  930.         break;
  931.     case 'd':
  932.     case 'D':
  933.     ifp->flags &= ~CONNECT_MODE;
  934.         break;
  935.     default:
  936.         tprintf("Usage: %s [vc | datagram]\n",argv[0]);
  937.         return 1;
  938.     }
  939.     return 0;
  940. }
  941.  
  942. #if     (!defined(MSDOS) || defined(ESCAPE))
  943. int
  944. doescape(argc,argv,p)
  945. int argc;
  946. char *argv[];
  947. void *p;
  948. {
  949.     if(argc < 2)
  950.         tprintf("0x%x\n",Escape);
  951.     else 
  952.         Escape = *argv[1];
  953.     return 0;
  954. }
  955. #endif  MSDOS
  956. /* Generate system command packet. Synopsis:
  957.  * remote [-p port#] [-k key] [-a hostname] <hostname> reset|exit|kickme
  958.  */
  959. int
  960. doremote(argc,argv,p)
  961. int argc;
  962. char *argv[];
  963. void *p;
  964. {
  965.     struct sockaddr_in fsock;
  966.     int s,c;
  967.     char *data,x;
  968.     int16 port,len;
  969.     char *key = NULLCHAR;
  970.     int klen;
  971.     int32 addr = 0;
  972.     char *cmd,*host;
  973.  
  974.     port = IPPORT_REMOTE;   /* Set default */
  975.     optind = 1;             /* reinit getopt() */
  976. #ifdef __GNUC__
  977.     klen = 0;        /* defeat spurious "uninitialized" warning */
  978. #endif
  979.     while((c = getopt(argc,argv,"a:p:k:s:")) != EOF){
  980.         switch(c){
  981.         case 'a':
  982.             if((addr = resolve(optarg)) == 0){
  983.         tprintf(Badhost,optarg);
  984.                 return -1;
  985.             }
  986.             break;
  987.         case 'p':
  988.             port = atoi(optarg);
  989.             break;
  990.         case 'k':
  991.             key = optarg;
  992.             klen = strlen(key);
  993.             break;
  994.         case 's':
  995.             Rempass = strdup(optarg);
  996.             return 0;       /* Only set local password */
  997.         }
  998.     }
  999.     if(optind > argc - 2){
  1000.         tprintf("Insufficient args\n");
  1001.         return -1;
  1002.     }
  1003.     host = argv[optind++];
  1004.     cmd = argv[optind];
  1005.     if((s = socket(AF_INET,SOCK_DGRAM,0)) == -1){
  1006.         tprintf("socket failed\n");
  1007.         return 1;
  1008.     }
  1009.     len = 1;
  1010.     /* Did the user include a password or kickme target? */
  1011.     if(addr != 0 && cmd[0] == 'k')
  1012.         len += sizeof(int32);
  1013.  
  1014.     if(key != NULLCHAR && (cmd[0] == 'r' || cmd[0] == 'e')) 
  1015.         len += klen;
  1016.  
  1017.     if(len == 1)
  1018.         data = &x;
  1019.     else
  1020.         data = mallocw((size_t)len);
  1021.  
  1022.     fsock.sin_family = AF_INET;
  1023.     if((fsock.sin_addr.s_addr = resolve(host)) == 0){
  1024.     tprintf(Badhost,host);
  1025.         goto cleanup;
  1026.     }
  1027.     fsock.sin_port = port;
  1028.  
  1029.     switch(cmd[0]){
  1030.     case 'r':
  1031.         data[0] = SYS_RESET;
  1032.         if(key != NULLCHAR)
  1033.             strncpy(&data[1],key,(size_t)klen);
  1034.         break;
  1035.     case 'e':
  1036.         data[0] = SYS_EXIT;
  1037.         if(key != NULLCHAR)
  1038.             strncpy(&data[1],key,(size_t)klen);
  1039.         break;
  1040.     case 'k':
  1041.         data[0] = KICK_ME;
  1042.         if(addr != 0)
  1043.             put32(&data[1],addr);
  1044.         break;
  1045.     default:
  1046.         tprintf("Unknown command %s\n",cmd);
  1047.         goto cleanup;
  1048.     }
  1049.     /* Form the command packet and send it */
  1050.     if(sendto(s,data,len,0,(char *)&fsock,sizeof(fsock)) == -1){
  1051.         tprintf("sendto failed: %s\n",sys_errlist[errno]);
  1052.         goto cleanup;
  1053.     }
  1054. cleanup:
  1055.     if(data != &x)
  1056.         free(data);
  1057.     close_s(s);
  1058.     return 0;
  1059. }
  1060.  
  1061. #if (defined(ALLCMD) || defined(ALLSESSIONS))
  1062. int
  1063. morecmd(argc,argv,p)
  1064. int argc;
  1065. char *argv[];
  1066. void *p;
  1067. {
  1068.     struct session *sp;
  1069.     FILE *fp;
  1070.     char buf[81],fname[128];
  1071.     int row;
  1072.     int usesession = 0;
  1073.  
  1074.     /* Use a session if this comes from console - WG7J*/
  1075. #ifdef __GNUC__
  1076.     row = 0;        /* defeat uninitialized warnings */
  1077.     sp = 0;
  1078. #endif
  1079.     if(Curproc->input == Command->input) {
  1080.     usesession = 1;
  1081.     if((sp = newsession(argv[1],MORE,0)) == NULLSESSION){
  1082.         return 1;
  1083.     }
  1084.     /* Put tty into raw mode so single-char responses will work */
  1085.     sp->ttystate.echo = sp->ttystate.edit = 0;
  1086.     row = Numrows - 1;
  1087.     }
  1088.  
  1089.     strcpy(fname,make_fname(Command->curdirs->dir,argv[1]));
  1090.     if((fp = fopen(fname,READ_TEXT)) == NULLFILE){
  1091.     tprintf(NoRead,fname,sys_errlist[errno]);
  1092.     if(usesession) {
  1093.         keywait(NULLCHAR,1);
  1094.         freesession(sp);
  1095.     }
  1096.     return 1;
  1097.     }
  1098.     while(fgets(buf,sizeof(buf),fp),!feof(fp)){
  1099.     if((argc < 3) || (strstr(buf,argv[2])!=NULLCHAR)) {
  1100.         tprintf("%s",buf);
  1101.         if(usesession) {
  1102.         if(row > 0 && --row == 0){
  1103.             row = keywait("--More--",0);
  1104.             switch(row){
  1105.             case -1:
  1106.             case 'q':
  1107.             case 'Q':
  1108.             goto done;
  1109.             case '\n':
  1110.             case '\r':
  1111.             row = 1;
  1112.             break;
  1113.             case ' ':
  1114.             default:
  1115.             row = Numrows - 1;
  1116.             }
  1117.         }
  1118.         }
  1119.         }
  1120.     }
  1121. done:   fclose(fp);
  1122.     if(usesession) {
  1123.     keywait(NULLCHAR,1);
  1124.     freesession(sp);
  1125.     }
  1126.     return 0;
  1127. }
  1128.  
  1129. int
  1130. domore(argc,argv,p)
  1131. int argc;
  1132. char *argv[];
  1133. void *p;
  1134. {
  1135.     char **pargv;
  1136.     int i;
  1137.  
  1138.     if(Curproc->input == Command->input) {
  1139.     /* Make private copy of argv and args,
  1140.      * spawn off subprocess and return.
  1141.      */
  1142.     pargv = (char **)callocw((size_t)argc,sizeof(char *));
  1143.     for(i=0;i<argc;i++)
  1144.         pargv[i] = strdup(argv[i]);
  1145.     newproc("more",512,(void (*)__ARGS((int,void *,void *)))morecmd,argc,(void *)pargv,p,1);
  1146.     } else
  1147.     morecmd(argc,argv,p);
  1148.     return 0;
  1149. }
  1150.  
  1151. #endif
  1152.  
  1153. #ifdef ALLCMD
  1154. int
  1155. dotail(argc,argv,p)
  1156. int argc;
  1157. char *argv[];
  1158. void *p;
  1159. {
  1160.     register int handle, i;
  1161.     register unsigned line = 0, rdsize = 2000;
  1162.     long length;
  1163.     char *buffer;
  1164.  
  1165.     buffer = callocw(2000, sizeof (char));
  1166.  
  1167.     if ((handle = open (argv[1], O_BINARY | O_RDONLY)) == -1) {
  1168.     tprintf(NoRead,argv[1],sys_errlist[errno]);
  1169.         free(buffer);
  1170.         return -1;
  1171.     }
  1172.     length = filelength(handle);
  1173.  
  1174.     if (length > 2000) {
  1175.         length -= 2000;
  1176.     } else {
  1177.         rdsize = (int) length;
  1178.         length = 0;
  1179.     }
  1180.  
  1181.     lseek (handle, length, SEEK_SET);
  1182.     if (read (handle, buffer, rdsize) == -1) {
  1183.     tprintf(NoRead,argv[1],sys_errlist[errno]);
  1184.         close(handle);
  1185.         free(buffer);
  1186.         return -1;
  1187.     }
  1188.  
  1189.     for (i = rdsize - 1; i > 0; i--) {
  1190.         if (buffer[i] == '\n')
  1191.             line++;
  1192.         if (line == 18)
  1193.             break;
  1194.     }
  1195.     for (; i < rdsize; i++)
  1196.         tputc(buffer[i]);
  1197.  
  1198.     tprintf("\n");
  1199.     close(handle);
  1200.     free(buffer);
  1201.     return 0;
  1202. }
  1203. #endif /*ALLCMD*/
  1204.  
  1205. /* No-op command */
  1206. int
  1207. donothing(argc,argv,p)
  1208. int argc;
  1209. char *argv[];
  1210. void *p;
  1211. {
  1212.     return 0;
  1213. }
  1214.  
  1215. static int SendError = 1;
  1216.  
  1217. int doerror(int argc,char *argv[],void *p) {
  1218.     return setbool(&SendError,"Mail errors",argc,argv);
  1219. }
  1220.  
  1221. /* Mail a system message to the sysop - WG7J */
  1222. void
  1223. mail_error(char *fmt, ...)
  1224. {
  1225.     FILE *wrk,*txt;
  1226.     va_list ap;
  1227.     char *cp;
  1228.     long t,msgid;
  1229.     char fn[128];
  1230.  
  1231.     if(!SendError)
  1232.     return;
  1233.  
  1234.     /* Get current time */
  1235.     time(&t);
  1236.  
  1237.     /* get the message id for this message */
  1238.     msgid = get_msgid();
  1239.  
  1240.     /* Create the smtp work file */
  1241.     sprintf(fn,"%s/%ld.wrk",Mailqdir,msgid);
  1242.     if((wrk = fopen(fn,"w")) == NULL)
  1243.     return;
  1244.  
  1245.      /* Create the smtp text file */
  1246.     sprintf(fn,"%s/%ld.txt",Mailqdir,msgid);
  1247.     if((txt = fopen(fn,"w")) == NULL) {
  1248.     fclose(wrk);
  1249.     return;
  1250.     }
  1251.  
  1252.     /* Fill in the work file */
  1253.     fprintf(wrk,"%s\nMAILER-DAEMON@%s\nsysop@%s",Hostname,Hostname,Hostname);
  1254.     fclose(wrk);
  1255.  
  1256.     /* Fill in the text file headers */
  1257.     fprintf(txt,"%s%s",Hdrs[DATE],ptime(&t));
  1258.     fprintf(txt,"%s<%ld@%s>\n",Hdrs[MSGID],msgid,Hostname);
  1259.     fprintf(txt,"%sMAILER-DAEMON@%s\n",Hdrs[FROM],Hostname);
  1260.     fprintf(txt,"%ssysop@%s\n",Hdrs[TO],Hostname);
  1261.     fprintf(txt,"%sSystem message\n\n",Hdrs[SUBJECT]);
  1262.  
  1263.     /* Print the text body */
  1264.     cp = ctime(&t);
  1265.     fprintf(txt,"On %s",cp);
  1266.     va_start(ap,fmt);
  1267.     vfprintf(txt,fmt,ap);
  1268.     va_end(ap);
  1269.     fprintf(txt,"\n");
  1270.     fclose(txt);
  1271.  
  1272.     /* Now kick the smtp server */
  1273.     smtptick(NULL);
  1274. }
  1275.  
  1276. /* Log messages of the form
  1277.  * Tue Jan 31 00:00:00 1987 44.64.0.7:1003 open FTP
  1278.  */
  1279. #if     defined(ANSIPROTO)
  1280. void
  1281. log(int s,char *fmt, ...)
  1282. {
  1283.     va_list ap;
  1284.     char *cp;
  1285.     long t;
  1286.     int i;
  1287.     struct sockaddr fsocket;
  1288. #ifdef  MSDOS
  1289.     int fd;
  1290. #endif
  1291.  
  1292.     if(Logfp == NULLFILE)
  1293.         return;
  1294.  
  1295.     time(&t);
  1296.     cp = ctime(&t);
  1297.     rip(cp);
  1298.     i = SOCKSIZE;
  1299.     fprintf(Logfp,"%s",cp);
  1300.     if(getpeername(s,(char *)&fsocket,&i) != -1)
  1301.         fprintf(Logfp," %s",psocket(&fsocket));
  1302.  
  1303.     fprintf(Logfp," - ");
  1304.     va_start(ap,fmt);
  1305.     vfprintf(Logfp,fmt,ap);
  1306.     va_end(ap);
  1307.     fprintf(Logfp,"\n");
  1308.     fflush(Logfp);
  1309. #ifdef  MSDOS
  1310.     /* MS-DOS doesn't really flush files until they're closed */
  1311.     fd = fileno(Logfp);
  1312.     if((fd = dup(fd)) != -1)
  1313.         close(fd);
  1314. #endif
  1315.  
  1316. }
  1317. #else
  1318. /*VARARGS2*/
  1319. void
  1320. log(s,fmt,arg1,arg2,arg3,arg4,arg5)
  1321. int s;
  1322. char *fmt;
  1323. int arg1,arg2,arg3,arg4,arg5;
  1324. {
  1325.     char *cp;
  1326.     long t;
  1327.     int fd,i;
  1328.     struct sockaddr fsocket;
  1329.  
  1330.     if(Logfp == NULLFILE)
  1331.         return;
  1332.     time(&t);
  1333.     cp = ctime(&t);
  1334.     rip(cp);
  1335.     i = SOCKSIZE;
  1336.     fprintf(Logfp,"%s",cp);
  1337.     if(getpeername(s,(char *)&fsocket,&i) != -1)
  1338.         fprintf(Logfp," %s",psocket(&fsocket));
  1339.  
  1340.     fprintf(Logfp," - ");
  1341.     fprintf(Logfp,fmt,arg1,arg2,arg3,arg4,arg5);
  1342.     fprintf(Logfp,"\n");
  1343.     fflush(Logfp);
  1344. #ifdef  MSDOS
  1345.     /* MS-DOS doesn't really flush files until they're closed */
  1346.     fd = fileno(Logfp);
  1347.     if((fd = dup(fd)) != -1)
  1348.         close(fd);
  1349. #endif
  1350. }
  1351. #endif
  1352.  
  1353. int
  1354. dosource(argc,argv,p)
  1355. int argc;
  1356. char *argv[];
  1357. void *p;
  1358. {
  1359.     int linenum = 0;
  1360.     char *inbuf,*intmp;
  1361.     FILE *fp;
  1362.  
  1363.     /* Read command source file */
  1364.     if((fp = fopen(argv[1],READ_TEXT)) == NULLFILE){
  1365.     tprintf(NoRead,argv[1],sys_errlist[errno]);
  1366.         return 1;
  1367.     }
  1368.  
  1369.     inbuf = malloc(BUFSIZ);
  1370.     intmp = malloc(BUFSIZ);
  1371.     while(fgets(inbuf,BUFSIZ,fp) != NULLCHAR){
  1372.         strcpy(intmp,inbuf);
  1373.         linenum++;
  1374.         if(Verbose)
  1375.             tprintf("%s",intmp);
  1376.         if(cmdparse(Cmds,inbuf,NULL) != 0){
  1377.             tprintf("*** file \"%s\", line %d: %s\n",
  1378.                 argv[1],linenum,intmp);
  1379.         }
  1380.     }
  1381.     fclose(fp);
  1382.     free(inbuf);
  1383.     free(intmp);
  1384.     return 0;
  1385. }
  1386.  
  1387. /* if unattended mode is set - restrict ax25, telnet and maybe other sessions */
  1388. int
  1389. doattended(argc,argv,p)
  1390. int argc;
  1391. char *argv[];
  1392. void *p;
  1393. {
  1394.     return setbool(&Attended,"Attended flag",argc,argv);
  1395. }
  1396.  
  1397. /* if ThirdParty is not set - restrict the mailbox (S)end command to local only */
  1398. int
  1399. dothirdparty(argc,argv,p)
  1400. int argc;
  1401. char *argv[];
  1402. void *p;
  1403. {
  1404.     return setbool(&ThirdParty,"Third-Party mail flag",argc,argv);
  1405. }
  1406.  
  1407. #ifdef ALLCMD
  1408. int
  1409. domdump(argc,argv,p)
  1410. int argc;
  1411. char *argv[];
  1412. void *p;
  1413. {
  1414.     unsigned int i;
  1415.     char * addr;
  1416.     unsigned int len = 8 * 16;      /* default is 8 lines of hex dump */
  1417.  
  1418.     if(argc < 2 || argc > 3) {
  1419.         tprintf("Usage:- dump <hex-address | .> [decimal-range] \n");
  1420.         return 0;
  1421.     }
  1422.     if(argv[1][0] == '.')
  1423.         addr = DumpAddr;                /* Use last end address */
  1424.     else
  1425.         addr = ltop(htol(argv[1]));     /* get address of item being dumped */
  1426.  
  1427.     if(argc == 3) {
  1428.         len = atoi(argv[2]);
  1429.         len = ((len + 15) >> 4) << 4;   /* round up to modulo 16 */
  1430.     }
  1431.  
  1432.     if(len < 1 || len > 256) {
  1433.         tprintf("Invalid dump range. Valid is 1 to 256\n");
  1434.         return 0;
  1435.     }
  1436. #ifdef UNIX
  1437.     tprintf("            Main Memory Dump Of Location %lx\n", FP_SEG(addr));
  1438. #else
  1439.     tprintf("            Main Memory Dump Of Location %Fp\n", addr);
  1440. #endif
  1441.     tprintf("Addr (offset)           Hexadecimal                         Ascii\n");
  1442.     tprintf("----                    -----------                         -----\n\n");
  1443.  
  1444.     for(i = 0; i < len; i += 16)
  1445.         fmtline((int16)i, (char *)(addr + i), 16);
  1446.     DumpAddr = (char *)(addr + i);          /* update address */
  1447.     return 0;
  1448. }
  1449.  
  1450. /* Print a buffer up to 16 bytes long in formatted hex with ascii
  1451.  * translation, e.g.,
  1452.  * 0000: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f  0123456789:;<=>?
  1453.  */
  1454. static void
  1455. fmtline(addr,buf,len)
  1456. int16 addr;
  1457. char *buf;
  1458. int16 len;
  1459. {
  1460.     char line[81];
  1461.     register char *aptr,*cptr;
  1462.     register char c;
  1463.  
  1464.     memset(line,' ',sizeof(line));
  1465.     ctohex(line,(int16)hibyte(addr));
  1466.     ctohex(line+2,(int16)lobyte(addr));
  1467.     aptr = &line[6];
  1468.     cptr = &line[55];
  1469.     while(len-- != 0){
  1470.         c = *buf++;
  1471.         ctohex(aptr,(int16)uchar(c));
  1472.         aptr += 3;
  1473.         c &= 0x7f;
  1474.         if((c > 0x1f) && (c < 0x7f))
  1475.             *cptr++ = c;
  1476.         else
  1477.             *cptr++ = '.';
  1478.     }
  1479.     *cptr++ = '\0';
  1480.     tprintf("%s\n",line);
  1481. }
  1482. /* Convert byte to two ascii-hex characters */
  1483. static void
  1484. ctohex(buf,c)
  1485. register char *buf;
  1486. register int16 c;
  1487. {
  1488.     static char hex[] = "0123456789abcdef";
  1489.  
  1490.     *buf++ = hex[hinibble(c)];
  1491.     *buf = hex[lonibble(c)];
  1492. }
  1493. #endif
  1494.  
  1495. int
  1496. dowrite(argc,argv,p)
  1497. int argc;
  1498. char *argv[];
  1499. void *p;
  1500. {
  1501.     int s;
  1502.     struct mbx *m;
  1503.  
  1504.     if((s = atoi(argv[1])) == 0) { /* must be a name */
  1505. #ifdef MAILBOX
  1506.     /* check the mailbox users */
  1507.     for(m=Mbox;m;m=m->next){
  1508.         if(!strcmp(m->name,argv[1]))
  1509.         break;
  1510.     }
  1511.     if(!m)
  1512.         return 0;
  1513.     s = m->user;
  1514. #else
  1515.     return 0;
  1516. #endif
  1517.     }
  1518.     usprintf(s,"*** Msg from SYSOP: %s\n",argv[2]);
  1519.     usflush(s);
  1520.  
  1521.     return 0;
  1522. }
  1523.  
  1524. #ifdef MAILBOX
  1525. /* write a message to all nodeshell users
  1526.  * argv[1] is the message.
  1527.  */
  1528. int
  1529. dowriteall(argc,argv,p)
  1530. int argc;
  1531. char *argv[];
  1532. void *p;
  1533. {
  1534.     register struct mbx *m;
  1535.  
  1536.     for(m=Mbox;m;m=m->next){
  1537.     usprintf(m->user,"*** Msg from SYSOP: %s\n",argv[1]);
  1538.     usflush(m->user);
  1539.     }
  1540.     return 0;
  1541. }
  1542. #endif
  1543.  
  1544.  
  1545. int
  1546. dostatus(argc,argv,p)
  1547. int argc;
  1548. char *argv[];
  1549. void *p;
  1550. {
  1551.     time_t nowtime, elapsedtime;
  1552.     unsigned int days,hrs,mins,secs;
  1553.  
  1554.     nowtime = time(&nowtime);                       /* current time */
  1555.     elapsedtime = nowtime - StartTime;              /* nos elapsed time */
  1556.  
  1557.     tprintf(Nosversion,Version);
  1558.     tputs(Version2);
  1559.     tprintf("Tty: %d rows, %d columns\n",Numrows,Numcols);
  1560.  
  1561. #ifdef  MSDOS
  1562.     tprintf(NosLoadInfo, _CS, _DS);
  1563. #endif
  1564.     tprintf("\nThe system time is %s", ctime(&nowtime));
  1565.     tprintf("NOS was started on %s\n", ctime(&StartTime));
  1566.     secs = elapsedtime % 60;
  1567.     elapsedtime = elapsedtime / 60;
  1568.     mins = elapsedtime % 60;
  1569.     elapsedtime = elapsedtime / 60;
  1570.     hrs = elapsedtime % 24;
  1571.     elapsedtime = elapsedtime / 24;
  1572.     days = elapsedtime;
  1573.     tprintf("Elapsed time => %u days:%02u hours:%02u minutes:%02u seconds.\n\n",days,hrs,mins,secs);
  1574. #ifdef ALLCMD
  1575.     tprintf("The station is currently %sttended.\n", Attended ? "A" : "Una");
  1576.     tprintf("The 'Message Of The Day' is ");
  1577.     if(Motd != NULLCHAR)
  1578.         tprintf("\n%s",Motd);
  1579.     else
  1580.         tprintf("not set!\n");
  1581. #endif
  1582. #ifdef  __TURBOC__
  1583.     dofstat();              /* print status of open files */
  1584. #endif
  1585.     return 0;
  1586. }
  1587.  
  1588. #ifdef ALLCMD
  1589. int
  1590. domotd(argc,argv,p)
  1591. int argc;
  1592. char *argv[];
  1593. void *p;
  1594. {
  1595.     if(argc > 2) {
  1596.         tprintf("Usage: motd \"<your message>\"\n");
  1597.         return 1;
  1598.     }
  1599.  
  1600.     if(argc < 2) {
  1601.         if(Motd != NULLCHAR) 
  1602.             tprintf("%s",Motd);
  1603.     } else {
  1604.         if(Motd != NULLCHAR){
  1605.             free(Motd);
  1606.             Motd = NULLCHAR;                /* reset the pointer */
  1607.         }
  1608.  
  1609.         if(!strlen(argv[1]))
  1610.             return 0;                       /* clearing the buffer */
  1611.  
  1612.         Motd = mallocw(strlen(argv[1])+5);      /* allow for the EOL char etc */
  1613.         strcpy(Motd, argv[1]);
  1614.         strcat(Motd, "\n");                     /* add the EOL char */
  1615.     }
  1616.     return 0;
  1617. }
  1618. #endif /*ALLCMD*/
  1619.  
  1620. #ifdef  __TURBOC__
  1621. /*
  1622.  * Fstat utility code.
  1623.  * Converted to go into NOS by Kelvin Hill - G1EMM  April 9, 1990
  1624.  */
  1625.  
  1626. extern unsigned char _osmajor;
  1627.  
  1628. static char    *localcopy(char far *);
  1629. static char    *progname(unsigned int);
  1630.  
  1631. int
  1632. dofstat()
  1633. {
  1634.     union REGS regs;
  1635.     struct SREGS segregs;
  1636.     char far *pfiletab, far * pnext, far * fp;
  1637.     char far *name, file[13], far * plist, far * entry;
  1638.     char ownername[9], ownerext[5];
  1639.     int nfiles, i, j, numhandles, entrylen;
  1640.     unsigned int access, devinfo, progpsp;
  1641.     long length, offset;
  1642.     int heading = 0;
  1643.  
  1644.     regs.h.ah = 0x52;       /* DOS list of lists */
  1645.     intdosx(®s, ®s, &segregs);
  1646.  
  1647.     /* make a pointer to start of master list */
  1648.     plist = (char far *) MK_FP(segregs.es, regs.x.bx);
  1649.  
  1650.     /* pointer to start of file table */
  1651.     pfiletab = (char far *) MK_FP(*(int far *) (plist + 6), *(int far *) (plist + 4));
  1652.  
  1653.     switch (_osmajor) {
  1654.     case 2:
  1655.         entrylen = 40;  /* DOS 2.x */
  1656.         break;
  1657.     case 3:
  1658.         entrylen = 53;  /* DOS 3.x */
  1659.         break;
  1660.     case 4:
  1661.     case 5:                 /* DOS 5.x - like dos 4.x */
  1662.     case 6:                 /* and NOW DOS 6.0 also */        
  1663.         entrylen = 59;  /* DOS 4.x - I do not know what is in the
  1664.                  * extra 6 bytes */
  1665.         break;
  1666.     default:
  1667. /*
  1668.     tprintf("Sorry, cannot handle this version of MS-DOS");
  1669. */
  1670.     return 1;
  1671.     }
  1672.  
  1673.     for (;;) {
  1674.         /* pointer to next file table */
  1675.         pnext = (char far *) MK_FP(*(int far *) (pfiletab + 2), *(int far *) (pfiletab + 0));
  1676.         nfiles = *(int far *) (pfiletab + 4);
  1677. #ifdef DEBUG
  1678.         tprintf("\nFile table at %Fp entries for %d files\n", pfiletab, nfiles);
  1679. #endif
  1680.         for (i = 0; i < nfiles; i++) {
  1681.  
  1682.             /*
  1683.              * cycle through all files, quit when we reach an
  1684.              * unused entry
  1685.              */
  1686.             entry = pfiletab + 6 + (i * entrylen);
  1687.             if (_osmajor >= 3) {
  1688.                 name = entry + 32;
  1689.                 strncpy(file, localcopy(name), 11);
  1690.                 file[11] = '\0';
  1691.                 numhandles = *(int far *) (entry + 0);
  1692.                 access = (int) *(char far *) (entry + 2);
  1693.                 length = *(long far *) (entry + 17);
  1694.                 offset = *(long far *) (entry + 21);
  1695.                 devinfo = *(int far *) (entry + 5);
  1696.                 progpsp = *(int far *) (entry + 49);
  1697.             } else {
  1698.                 name = entry + 4;
  1699.                 strncpy(file, localcopy(name), 11);
  1700.                 file[11] = '\0';
  1701.                 numhandles = (int) *(char far *) (entry + 0);
  1702.                 access = (int) *(char far *) (entry + 1);
  1703.                 length = *(long far *) (entry + 19);
  1704.                 offset = *(long far *) (entry + 36);
  1705.                 devinfo = (int) *(char far *) (entry + 27);
  1706.             }
  1707.             if ((strlen(file) > 0) && (numhandles > 0) && !(devinfo & 0x80)) {
  1708.                 if(!heading) {
  1709.                     tprintf("\n");
  1710.                     tprintf("                 Table of Open Files.\n");
  1711.                     tprintf("                 --------------------\n");
  1712.                     tprintf("Name           length   offset hnd acc PSP device type/owner\n");
  1713.                     tprintf("----           ------   ------ --- --- --- -----------------\n");
  1714.                     heading++;              /* header now printed */
  1715.                 }
  1716.                 tprintf("%8.8s.%3.3s %8ld %8ld  %2d ",
  1717.                        file, &file[8], length, offset, numhandles);
  1718.                 switch (access) {
  1719.                 case 0:
  1720.                     tprintf("r  ");
  1721.                     break;
  1722.                 case 1:
  1723.                     tprintf("w  ");
  1724.                     break;
  1725.                 case 2:
  1726.                     tprintf("rw ");
  1727.                     break;
  1728.                 default:
  1729.                     tprintf("   ");
  1730.                 }
  1731.                 if (_osmajor >= 3)
  1732.                     tprintf("%04X ", progpsp);
  1733.                 else
  1734.                     tprintf("---- ");
  1735.                 tprintf("drive %c: ", 'A' + (devinfo & 0x1F));
  1736.                 if (devinfo & 0x8000)
  1737.                     tprintf("(network) ");
  1738.                 if (_osmajor >= 3) {
  1739.                     /*
  1740.                      * only DOS 3+ can find out
  1741.                      * the name of the program
  1742.                      */
  1743.                     fnsplit(progname(progpsp), NULL, NULL, ownername, ownerext);
  1744.                     tprintf("   [%s%s]\n", strlwr(ownername), strlwr(ownerext));
  1745.                 } else {
  1746.                     tprintf("\n");
  1747.                 }
  1748.             }
  1749.             if (strlen(file) == 0)
  1750.                 return 0;
  1751.         }
  1752.         pfiletab = pnext;
  1753.     }
  1754. }
  1755.  
  1756. /* Make a copy of a string pointed to by a far pointer */
  1757. static char *
  1758. localcopy(s)
  1759. char far *s;
  1760. {
  1761.     static char localstring[256];
  1762.     char far *p = s;
  1763.     char *l = localstring;
  1764.     int i = 0;
  1765.  
  1766.     while (*p != NULL && i++ < 255) {
  1767.         *l++ = *p++;
  1768.     }
  1769.  
  1770.     *l = '\0';
  1771.  
  1772.     return (localstring);
  1773. }
  1774.  
  1775. /*
  1776.  * Return a near pointer to a character string with the full path name of the
  1777.  * program whose PSP is given in the argument.  If the argument is invalid,
  1778.  * this may return gibberish but I don't know how to tell Offset 0x2C in the
  1779.  * PSP in the segment address of the environment of a program.  Beyond the
  1780.  * last environment string is a null marker, a word count (usually 1), then
  1781.  * the full pathname of the owner of the environment This only works for DOS
  1782.  * 3+
  1783.  */
  1784. static char *
  1785. progname(pid)
  1786. unsigned int pid;
  1787. {
  1788.     unsigned far   *envsegptr;      /* Pointer to seg address of
  1789.                      * environment */
  1790.     char far       *envptr; /* Pointer to pid's environment  */
  1791.     unsigned far   *envsizeptr;     /* Pointer to environment size */
  1792.     unsigned        envsize;/* Size of pid's environment */
  1793.     unsigned        ppid;   /* Parent psp address */
  1794.  
  1795.     /* find the parent process psp at offset 0x16 of the psp */
  1796.     ppid = *(unsigned far *) MK_FP(pid, 0x16);
  1797.  
  1798.     /* find the environment at offset 2Ch of the psp */
  1799.     envsegptr = (unsigned far *) MK_FP(pid, 0x2C);
  1800.     envptr = (char far *) MK_FP(*envsegptr, 0);
  1801.  
  1802.     /*
  1803.      * Make a pointer that contains the size of the environment block.
  1804.      * Must point back one paragraph (to the environments MCB plus three
  1805.      * bytes forward (to the MCB block size field).
  1806.      */
  1807.     envsizeptr = (unsigned far *) MK_FP(*envsegptr - 1, 0x3);
  1808.     envsize = *envsizeptr * 16;     /* x 16 turns it into bytes */
  1809.  
  1810.     while (envsize > 0) {
  1811.         /* search for end of environment block, or NULL */
  1812.         while (--envsize && *envptr++);
  1813.  
  1814.         /*
  1815.          * Now check for another NULL immediately following the first
  1816.          * one located and a word count of 0001 following that.
  1817.          */
  1818.         if (!*envptr && *(unsigned far *) (envptr + 1) == 0x1) {
  1819.             envptr += 3;
  1820.             break;
  1821.         }
  1822.     }
  1823.  
  1824.     if (envsize > 0) {
  1825.         /* Owner name found - return it */
  1826.         return (localcopy(envptr));
  1827.     } else {
  1828.         if (pid == ppid) {
  1829.             /*
  1830.              * command.com doesn't leave it's name around, but if
  1831.              * pid = ppid then we know we have a shell
  1832.              */
  1833.             return ("-shell-");
  1834.         } else {
  1835.             return ("unknown");
  1836.         }
  1837.     }
  1838. }
  1839. #endif /*__TURBOC__*/
  1840.  
  1841. int
  1842. doprompt(argc,argv,p)
  1843. int argc;
  1844. char *argv[];
  1845. void *p;
  1846. {
  1847.     return setbool(&DosPrompt,"prompt",argc,argv);
  1848. }
  1849.  
  1850. /* Command history, see also pc.c - WG7J */
  1851. void logcmd(char *cmd) {
  1852.     struct hist *new;
  1853.     char *cp;
  1854.  
  1855.     if(!Maxhistory)     /* don't keep history */
  1856.     return;
  1857.  
  1858.     /* Get rid of \n; this is also done in cmdparse().
  1859.      * We HAVE to do this here, since the string is NOT null-terminated when
  1860.      * it comes from recv_mbuf()  !!!! rip() makes it nullterminated.
  1861.      */
  1862.     rip(cmd);
  1863.     cp = cmd;
  1864.     while(*cp == ' ' || *cp == '\t')
  1865.     cp++;
  1866.     if(!*cp)     /* Empty command */
  1867.     return;
  1868.  
  1869.     if(Histrysize < Maxhistory) {     /* Add new one */
  1870.     Histrysize++;
  1871.     if(!Histry) {           /* Empty list */
  1872.         /* Initialize circular linked list */
  1873.         Histry = mallocw(sizeof(struct hist));
  1874.         Histry->next = Histry->prev = Histry;
  1875.     } else {
  1876.         new = mallocw(sizeof(struct hist));
  1877.         /* Now link it in */
  1878.         Histry->next->prev = new;
  1879.         new->next = Histry->next;
  1880.         new->prev = Histry;
  1881.         Histry->next = new;
  1882.         Histry = new;
  1883.     }
  1884.     } else {
  1885.     /* Maximum number stored already, use the oldest entry */
  1886.     Histry = Histry->next;
  1887.     free(Histry->cmd);
  1888.     }
  1889.     Histry->cmd = strdup(cp);
  1890. }
  1891.  
  1892. int
  1893. dohistory(int argc,char *argv[],void *p) {
  1894.     struct hist *h;
  1895.     int num;
  1896.  
  1897.     if(argc > 1) {
  1898.     Maxhistory = atoi(argv[1]);
  1899.     return 0;
  1900.     }
  1901.     tprintf("Max recall %d\n",Maxhistory);
  1902.     if((h = Histry) == NULL)
  1903.     return 0;
  1904.     num = 0;
  1905.     do {
  1906.     tprintf("%.2d: %s\n",num++,h->cmd);
  1907.     h = h->prev;
  1908.     } while(h != Histry);
  1909.     return 0;
  1910. }
  1911.  
  1912. #ifndef UNIX
  1913.  
  1914. /* This adds some additional checks to the fopen()
  1915.  * in the Borland C++ Run Time Library.
  1916.  * It fixes problem with users trying to open system devices like
  1917.  * CON, AUX etc and hang a system.
  1918.  * WG7J, 930205
  1919.  */
  1920. #undef fopen
  1921. FILE _FAR *_Cdecl fopen(const char _FAR *__path, const char _FAR *__mode);
  1922.  
  1923. static char *InvalidName[] = {
  1924.     "NUL",
  1925.     "CON",
  1926.     "AUX",
  1927.     "PRN",
  1928.     "LPT1",
  1929.     "LPT2",
  1930.     "LPT3",
  1931.     "COM1",
  1932.     "COM2",
  1933.     "COM3",
  1934.     "COM4",
  1935.     "MOUSE$",
  1936.     "CLOCK$",
  1937.     NULLCHAR,
  1938. };
  1939.  
  1940. FILE *newfopen (const char *filename, const char *type) {
  1941.     int i;
  1942.  
  1943.     for(i=0;InvalidName[i] != NULLCHAR;i++)
  1944.     if(stricmp(InvalidName[i],filename) == 0)
  1945.         return NULL;
  1946.  
  1947.     return fopen (filename, type);
  1948. }
  1949.  
  1950. #endif
  1951.  
  1952. #if defined(__TURBOC__) && !defined(__BORLANDC__)
  1953. /* N5KNX: TurboC 2.0 lacks _setcursortype(), which we supply here for dorepeat */
  1954. void _setcursortype(int style)
  1955. {
  1956. /* From TurboC++ conio.h: */
  1957. #define _NOCURSOR      0
  1958. #define _SOLIDCURSOR   1
  1959. #define _NORMALCURSOR  2
  1960.  
  1961. /* Int 0x10 reg cx codes: */
  1962. #define   STD_CURSOR      0x0607
  1963. #define   BLK_CURSOR      0x0006
  1964. #define   NO_CURSOR       0x2607
  1965.  
  1966. union REGS regs;
  1967.  
  1968.  if (style == _NOCURSOR) regs.x.cx = NO_CURSOR;
  1969.  else if (style == _SOLIDCURSOR) regs.x.cx = BLK_CURSOR;
  1970.  else if (style == _NORMALCURSOR) regs.x.cx = STD_CURSOR;
  1971.  else return;
  1972.  regs.x.ax = 0x0100; /* set cursor */
  1973.  int86(0x10, ®s, ®s);
  1974. }
  1975. #endif
  1976.  
  1977. /* Repeat a command - taken from 930104 KA9Q NOS
  1978.    WA3DSP 1/93
  1979. */
  1980. int
  1981. dorepeat(argc,argv,p)
  1982. int argc;
  1983. char *argv[];
  1984. void *p;
  1985. {
  1986.     int32 interval;
  1987.     int ret;
  1988.     struct session *sp;
  1989.  
  1990.     if(isdigit(argv[1][0])){
  1991.     interval = atol(argv[1]);
  1992.     argc--;
  1993.     argv++;
  1994.     } else {
  1995.     interval = MSPTICK;
  1996.     }
  1997.     if((sp = newsession(argv[2],REPEAT,1)) == NULLSESSION){
  1998.     tprintf("Too many sessions\n");
  1999.     return 1;
  2000.     }
  2001.     _setcursortype(_NOCURSOR);
  2002.     while(sp==Current){
  2003.     /*  clrscr(); */
  2004.     /* gotoxy seems to work better - turn cursor off?? */
  2005.     gotoxy(1,1);
  2006.     ret = subcmd(Cmds,argc,argv,p);
  2007.     if(ret != 0 || pause(interval) == -1)
  2008.         break;
  2009.     }
  2010.     _setcursortype(_NORMALCURSOR);
  2011.     freesession(sp);
  2012.     return 0;
  2013. }
  2014.  
  2015.